﻿using Microsoft.AspNetCore.Builder;
using System;
using System.Collections.Generic;
using Quartz;
using Quartz.Impl;
using System.Threading.Tasks;
using DotNetExtensions.Core.Jobs;
using System.Linq;
using Microsoft.Extensions.Logging;
using DotNetExtensions.Core.Logging;
using DotNetExtensions.Core.Autofac;

namespace DotNetExtensions.Core.Quartz
{
    public class QuartzBuilder : Singleton<QuartzBuilder>
    {
        private StdSchedulerFactory factory = new StdSchedulerFactory();
        public readonly List<JobInfo> JobInfos;
        private ILogger logger;
        private QuartzBuilder()
        {
            JobInfos = new List<JobInfo>();
            logger = LoggerManager.GetLogger("QuartzBuilder");
        }

        public async Task Start()
        {
            IScheduler scheduler = await factory.GetScheduler();
            if (scheduler.IsStarted == false) await scheduler.Start();
        }

        private async Task ScheduleJob(JobInfo jobInfo, IScheduler scheduler)
        {
            if (jobInfo.Disabled == true) return;
            bool exists = await scheduler.CheckExists(new JobKey(jobInfo.JobId));
            if (exists) return;

            IJobDetail job = JobBuilder.Create(jobInfo.Type).WithIdentity(jobInfo.JobId).Build();
            foreach (var item in jobInfo.DataMap)
            {
                job.JobDataMap.Add(item.Key, item.Value);
            }
            var triggers = new List<ITrigger>();
            foreach (var cron in jobInfo.Crons)
            {
                ITrigger trigger = TriggerBuilder.Create().WithIdentity(jobInfo.JobId).WithCronSchedule(cron).Build();
                triggers.Add(trigger);
            }
            JobInfos.Add(jobInfo);
            await scheduler.ScheduleJob(job, triggers, replace: true);
            logger.LogInformation("定时任务[{0}]启动成功", jobInfo.JobId);
        }
        private async Task ScheduleJob(JobInfo jobInfo)
        {
            IScheduler scheduler = await factory.GetScheduler();
            await ScheduleJob(jobInfo, scheduler);
        }

        private async Task Delete(string jobId)
        {
            IScheduler scheduler = await factory.GetScheduler();
            IJobDetail job = await scheduler.GetJobDetail(new JobKey(jobId));
            if (job == null) return;

            await scheduler.PauseTrigger(new TriggerKey(jobId));
            await scheduler.PauseJob(new JobKey(jobId));
            await scheduler.UnscheduleJob(new TriggerKey(jobId));
            await scheduler.DeleteJob(new JobKey(jobId));
            await scheduler.Clear();

            logger.LogInformation("定时任务[{0}]停止成功", jobId);
        }

        public static bool Exists(JobInfo jobInfo)
        {
            return Default.JobInfos.Any(c => c.JobId == jobInfo.JobId);
        }
        public static bool IsSchedule(JobInfo jobInfo)
        {
            return Default.JobInfos.Any(c => c.JobId == jobInfo.JobId && c.IsSchedule == true);
        }
        public static async Task Add(JobInfo jobInfo)
        {
            await Default.ScheduleJob(jobInfo);
        }
        public static async Task Remove(string jobId)
        {
            await Default.Delete(jobId);
        }
    }
    public static class QuartzBuilderExtensions
    {
        public static void UseQuartz<T>(this IApplicationBuilder app)
        {
            QuartzBuilder.Default.Start().Wait();
            if (RegistTypeResolver.Default.RegistTypes.TryGetValue(typeof(T), out List<Type> types))
            {
                foreach (var item in types)
                {
                    var jobInfo = JobResolver.Resolve(item);
                    if (jobInfo == null) continue;
                    QuartzBuilder.Add(jobInfo).Wait();
                }
            }
        }
    }
}
